﻿using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using System;
using System.Linq;
using wRPC;
using wRPC.DataLogic;

namespace wRPCService
{
    /// <summary>
    /// 统一返回结果，你也可以自定义实现一个，也可以继续使用TRY
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class UnifyResultAttribute : AopAttribute
    {
        public bool DontUse { get; set; } = false;
        /// <summary>
        /// Try放到第一位
        /// </summary>
        public override int Order { get; set; } = int.MinValue;
        public override bool OnActionExecuted(AopContext context)
        {
            if (DontUse) return true;
            var o = new ApiResult<object>() { code = 200, message = "操作成功" };
            if (context.Exception is null)
            {
                o.data = context.Result;
            }
            else
            {
                context.Exception = context.Exception.GetBaseException();
                //异步改同步在这里判断异常类型
                if (context.Exception is ApiException e)
                {
                    o.code = 0;
                    o.message = $"操作失败：{e.Message}";
                    o.errData = e.data;
                }
                else
                {
                    o.code = 500;
                    o.message = $"接口调用异常：{context.Exception.Message}";
                    o.errData = context.Exception.StackTrace;
                }
            }
            context.Result = o;
            return base.OnActionExecuted(context);
        }
    }
    /// <summary>
    /// 内存缓存特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class MemoryCacheAttribute : AopAttribute
    {
        /// <summary>
        /// 缓存键，默认则为方法名+参数哈希。
        /// </summary>
        public string Key { get; set; }
        /// <summary>
        /// 缓存滑动窗口，单位秒，默认60秒，取消请使用-1。
        /// </summary>
        public int SlidingExpiration { get; set; } = 60;
        /// <summary>
        /// 缓存固定窗口，单位秒，默认3600秒（60分钟），取消请使用-1，因此无法支持整点这样的需求
        /// </summary>
        public int AbsoluteExpiration { get; set; } = 3600;
        /// <summary>
        /// 缓存依赖，其他缓存键
        /// </summary>
        public string[] DependCache { get; set; }
        /// <summary>
        /// 获取缓存键
        /// </summary>
        /// <returns>缓存键</returns>
        private object GetKey(AopContext context)
        {
            if (string.IsNullOrWhiteSpace(Key))
            {
                var param = string.Join("_", context.Parameters.Select(p => JsonConvert.SerializeObject(p).GetHashCode()));
                Key = $"{context.Method.ReflectedType.FullName}_{context.Method.ReflectedType.AssemblyQualifiedName.GetHashCode()}_{context.Method.Name}_{param}";
            }
            return Key;
        }
        public override int Order { get; set; } = int.MaxValue;
        /// <summary>
        /// 是否存在缓存
        /// </summary>
        private bool hasCache = false;
        public override bool OnActionExecuting(AopContext context)
        {
            if (CacheManager._cache.TryGetValue(this.GetKey(context), out var o))
            {
                hasCache = true;
                context.Result = o;
                return false;
            }
            else
            {
                hasCache = false;
                return true;
            }
        }

        public override bool OnActionExecuted(AopContext context)
        {
            if (context.Exception is null && hasCache == false)
            {
                CacheManager._cache.Set(this.GetKey(context), context.Result,
                    CacheManager.CreateCachePolicy(
                        AbsoluteExpiration == -1 ? TimeSpan.Zero : TimeSpan.FromSeconds(AbsoluteExpiration),
                        SlidingExpiration == -1 ? TimeSpan.Zero : TimeSpan.FromSeconds(SlidingExpiration),
                        DependCache));
            }
            return base.OnActionExecuted(context);
        }
    }
}
